﻿#include "FCAbstractNode.h"
#include "FCAbstractNodeGraphicsItem.h"
#include "FCNodeMetaData.h"



class FCAbstractNodePrivate {
    FC_IMPL_PUBLIC(FCAbstractNode)
public:
    class LinkData {
public:
        LinkData();
        LinkData(std::shared_ptr<FCAbstractNode> n, const QString& p);
        std::weak_ptr<FCAbstractNode> node;
        QString key;
    };
public:
    FCAbstractNodePrivate(FCAbstractNode *p);
    FCNodeMetaData _meta;
    FCAbstractNodeGraphicsItem *_item;              ///< 记录从节点生成的item
    QMap<QString, LinkData> _toNode;                ///< 所有output连接点对应的node,这里的linkData都是其他
    QMap<QString, LinkData> _fromNode;              ///< 所有input连接点对应的node
    QMap<QString, FCDataPackage> _inputData;        ///< 节点数据
};

FCAbstractNodePrivate::LinkData::LinkData()
{
}


FCAbstractNodePrivate::LinkData::LinkData(std::shared_ptr<FCAbstractNode> n, const QString& p)
    : node(n), key(p)
{
}


FCAbstractNodePrivate::FCAbstractNodePrivate(FCAbstractNode *p) : q_ptr(p)
    , _item(nullptr)
{
}


FCAbstractNode::FCAbstractNode() : d_ptr(new FCAbstractNodePrivate(this))
{
}


/**
 * @brief 节点的销毁，节点销毁过程会通知相关联的节点把自己信息解除
 */
FCAbstractNode::~FCAbstractNode()
{
    //析构时断开时要清空关系
    for (auto i = d_ptr->_toNode.begin(); i != d_ptr->_toNode.end(); ++i)
    {
        detachToLink(i.key());
    }
    QList<QString> fromkeys = d_ptr->_fromNode.keys();
    QList<FCAbstractNodePrivate::LinkData> lds = d_ptr->_fromNode.values();

    for (FCAbstractNodePrivate::LinkData ld : lds)
    {
        Pointer p = ld.node.lock();
        if (p) {
            p->detachToLink(ld.key);
        }
    }
}


/**
 * @brief 获取节点的名字
 * @return
 */
QString FCAbstractNode::getNodeName() const
{
    return (d_ptr->_meta.getNodeName());
}


void FCAbstractNode::setNodeName(const QString& name)
{
    d_ptr->_meta.setNodeName(name);
}


/**
 * @brief FCAbstractNode::getNodePrototype
 * @return
 */
QString FCAbstractNode::getNodePrototype() const
{
    return (d_ptr->_meta.getNodePrototype());
}


/**
 * @brief FCAbstractNodeGraphicsItem::getIcon
 * @return
 */
QIcon FCAbstractNode::getIcon() const
{
    return (d_ptr->_meta.getIcon());
}


/**
 * @brief 设置图标
 * @param icon
 */
void FCAbstractNode::setIcon(const QIcon& icon)
{
    d_ptr->_meta.setIcon(icon);
}


/**
 * @brief 获取节点元数据
 * @return
 */
const FCNodeMetaData& FCAbstractNode::metaData() const
{
    return (d_ptr->_meta);
}


/**
 * @brief 获取节点元数据
 * @return
 */
FCNodeMetaData& FCAbstractNode::metaData()
{
    return (d_ptr->_meta);
}


/**
 * @brief 设置元数据
 * @param metadata
 */
void FCAbstractNode::setMetaData(const FCNodeMetaData& metadata)
{
    d_ptr->_meta = metadata;
}


/**
 * @brief 返回自身的引用
 * @return
 */
FCAbstractNode::Pointer FCAbstractNode::pointer()
{
    return (shared_from_this());
}


/**
 * @brief 建立连接,从out到另外一个item的in
 * @param outpt 输出点
 * @param toItem 输入的item
 * @param topt 输入点
 * @return 成功返回true
 */
bool FCAbstractNode::linkTo(const QString& outpt, FCAbstractNode::Pointer toItem, const QString& inpt)
{
    if (!getOutputKeys().contains(outpt)) {
        qDebug()<< "invalid link node[" << getNodeName() <<  "] can not find out key " << outpt;
        return (false);
    }
    if (!(toItem->getInputKeys().contains(inpt))) {
        qDebug()<< "invalid link node[" << getNodeName() <<  "] toItem can not find inpt " << inpt;
        return (false);
    }
    FCAbstractNodePrivate::LinkData ld;

    ld.node = toItem;
    ld.key = inpt;
    d_ptr->_toNode.insert(outpt, ld);
    toItem->d_func()->_fromNode.insert(inpt, FCAbstractNodePrivate::LinkData(pointer(), outpt));
    return (true);
}


bool FCAbstractNode::detachToLink(const QString& outpt)
{
    FCAbstractNodePrivate::LinkData ld = d_ptr->_toNode.value(outpt);
    Pointer toItem = ld.node.lock();

    if (toItem == nullptr) {
        return (d_ptr->_toNode.remove(outpt) > 0);
    }
    toItem->d_func()->_fromNode.remove(ld.key);
    return (d_ptr->_toNode.remove(outpt) > 0);
}


/**
 * @brief 获取node对应的item
 * @return
 */
FCAbstractNodeGraphicsItem *FCAbstractNode::graphicsItem()
{
    return (d_ptr->_item);
}


const FCAbstractNodeGraphicsItem *FCAbstractNode::graphicsItem() const
{
    return (d_ptr->_item);
}


/**
 * @brief @sa createGraphicsItem 最后需调用此函数记录生成的item
 * @param item 内部维护着FCAbstractNode的weakpoint
 */
void FCAbstractNode::registGraphicsItem(FCAbstractNodeGraphicsItem *item)
{
    d_ptr->_item = item;
}


/**
 * @brief 调用FCAbstractNodeGraphicsItem的nodeAction函数，把节点的动作传递到item中
 * @param item
 * @param act
 * @param v
 */
void FCAbstractNode::callItemNodeHasAction(FCAbstractNode::NodeAction act, const QVariant& v)
{
    FCAbstractNodeGraphicsItem *item = graphicsItem();

    if (item) {
        item->nodeAction((int)act, v);
    }
}


/**
 * @brief 输入参数
 * @param inputName
 * @param dp 数据会发生拷贝操作，不会影响原来数据包
 */
void FCAbstractNode::input(const QString& key, FCDataPackage dp)
{
    d_ptr->_inputData[key] = dp.copy();
    callItemNodeHasAction(NodeInputed, key);
}


/**
 * @brief FCAbstractNode::inputData
 * @param key
 * @return
 */
FCDataPackage FCAbstractNode::inputData(const QString& key)
{
    return (d_ptr->_inputData.value(key));
}
